import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { FormBuilder,  UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { MenuDto } from 'src/app/models/sys/menu.dto';
import { NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ApiService } from 'src/app/services/api.service';
import { MenuQueryParam } from 'src/app/models/param/menu-query.param';
import { Consts } from 'src/app/consts/consts';
import { DictDto } from 'src/app/models/sys/dict.dto';

import { IconDefinition } from '@ant-design/icons-angular';
import { NZ_ICONS } from 'ng-zorro-antd/icon';
import { AddMenuParam } from 'src/app/models/param/add-menu.param';
import { EditMode } from 'src/app/models/enums/edit-mode.enum';
import { UpdateMenuParam } from 'src/app/models/param/update-menu.param';

const PARENT_ID = 'parentId';
const MENU_TYPE = 'menuType';
const MENU_NAME = 'menuName';
const PERMS = 'perms';
const PATH = 'path';
const ORDER_NUM = 'orderNum';
const ICON = 'icon';
const ENABLED = 'enabled';

@Component({
  selector: 'app-add-menu',
  templateUrl: './add-menu.component.html',
  styleUrl: './add-menu.component.less'
})
export class AddMenuComponent implements OnInit {
  @Input() modeSubject!: BehaviorSubject<{mode: EditMode, menu?: MenuDto, parent?: MenuDto}>;
  @Output() addMenuEvent = new EventEmitter<boolean>();

  // 新建还是编辑
  menu?: MenuDto;
  modeEnum = EditMode;
  editMode = EditMode.ADD;
  // 在某权限下新建子权限时，parentValue为某权限ID.编辑时，为被编辑权限的parentId
  parentValue?: string;

  // Form fields
  addForm!: UntypedFormGroup;
  menuTypes: DictDto[] = [];
  icons: string[] = [];
  // icons = ["down", "up", "copy","scissor","delete","snippets","diff","highlight",
  // "forward", "bold", "italic","underline","strikethrough","redo"];
  selectedIcon = "down";
  submitted = false;

  //Tree
  menus: MenuDto[] = [];
  menuNodes: NzTreeNodeOptions[] = [];
  selectedNodes?: string;

  expandKeys = [];

  constructor(private _api: ApiService,
    private _fb: FormBuilder,
    private _message: NzMessageService,
    @Inject(NZ_ICONS) private _icons: IconDefinition[]) {
    console.log(`Inject icon with ${this.icons.length}`);
  }

  ngOnInit(): void {
    this.icons = this._icons.map(i => i.name);
    this.createAddForm();
    this.getMenuTypes();
  }

  createAddForm() {
    this.addForm = this._fb.group({});
    this.addForm.addControl(PARENT_ID, new UntypedFormControl(''));
    this.addForm.addControl(MENU_TYPE, new UntypedFormControl(''));
    this.addForm.addControl(MENU_NAME, new UntypedFormControl('', [Validators.minLength(2), Validators.maxLength(40)]));
    this.addForm.addControl(PERMS, new UntypedFormControl('', [Validators.minLength(2), Validators.maxLength(45)]));
    this.addForm.addControl(PATH, new UntypedFormControl(''));
    this.addForm.addControl(ORDER_NUM, new UntypedFormControl(''));
    this.addForm.addControl(ICON, new UntypedFormControl(''));
    this.addForm.addControl(ENABLED, new UntypedFormControl(''));

    console.log(`createAddForm type of ${typeof this.modeSubject}`);
    this.modeSubject.subscribe((value) => {
      this.editMode = value.mode;

      if (this.editMode == EditMode.ADD) {
        this.addForm.get(MENU_TYPE)?.addValidators([Validators.required]);
        this.addForm.get(MENU_NAME)?.addValidators([Validators.required]);
      
        if (value.parent != null) {
          console.log(`add menu with parent :${value.parent}`);
          this.parentValue = String(value.parent.menuId!);
        }
        this.getMenus();
      } else {
        this.menu = value.menu!;
        this.selectedIcon = this.menu.icon;
        this.initParam(this.menu!);
      }
    });
  }

  initParam(menu: MenuDto) {
    this.parentValue = String(menu.parentId);
    this.addForm.get(MENU_TYPE)?.patchValue(menu.menuType);
    this.addForm.get(MENU_NAME)?.patchValue(menu.menuName);
    this.addForm.get(PERMS)?.patchValue(menu.perms);
    this.addForm.get(PATH)?.patchValue(menu.path);

    this.addForm.get(ORDER_NUM)?.patchValue(menu.orderNum);
    this.addForm.get(ICON)?.patchValue(menu.icon);
    this.addForm.get(ENABLED)?.patchValue(menu.enabled);
  }

  getMenus() {
    const param = new MenuQueryParam();
    param.pageNum = 1;
    param.pageSize = 10000;

    this._api.getMenuTree(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        this.menus = resp.data;
        this.convertToTreeNodes(this.menus);
      }
    });
  }

  getMenuTypes() {
    this._api.getMenuType().subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        this.menuTypes = resp.data;
      }
    });
  }

  convertToTreeNodes(depts: MenuDto[]) {
    this.menuNodes = [];

    for (const dept of depts) {
      const node = this.convertToTreeNode(dept);
      console.log(`convert parent ${node.key}`);
      this.menuNodes.push(node);
    }
  }

  convertToTreeNode(dept: MenuDto): NzTreeNodeOptions {
    const result: NzTreeNodeOptions = {
      title: dept.menuName,
      key: dept.menuId.toString(),
    }

    if (dept.children) {
      const nodeChildren: NzTreeNodeOptions[] = [];
      for (const child of dept.children) {
        const nodeChild = this.convertToTreeNode(child);
         console.log(`add child ${nodeChild.key} to parent ${result.key}`);
        nodeChildren.push(nodeChild);
      }
      result.children = nodeChildren;
    }

    return result;
  }

  get fm() {
    return this.addForm.controls;
  }

  onCreate() {
    this.submitted = true;
    if (!this.addForm.valid) {
      return;
    }

    const param = new AddMenuParam();
    param.menuType = this.addForm.get(MENU_TYPE)?.value;
    param.menuName = this.addForm.get(MENU_NAME)?.value;
    param.perms = this.addForm.get(PERMS)?.value;
    param.icon = this.addForm.get(ICON)?.value;
    param.path = this.addForm.get('path')?.value;
    if (this.parentValue != null) {
      param.parentId = Number(this.parentValue);
    }

    this.doCreate(param);
  }

  doCreate(param: AddMenuParam) {
    this._api.addMenu(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK) {
        this._message.info("add Ok");
        this.resetModal();
        this.addMenuEvent.emit(true);
      } else {
        this._message.warning("add error: " + resp.message);
      }
    });
  }

  onUpdate() {
    this.submitted = true;
    if (this.menu == null || !this.addForm.valid) {
      return;
    }

    const param = new UpdateMenuParam();
    param.menuId = this.menu!.menuId;

    param.menuName = this.addForm.get(MENU_NAME)?.dirty ? this.addForm.get(MENU_NAME)?.value : undefined;
    param.parentId = this.addForm.get(PARENT_ID)?.dirty ? this.addForm.get(PARENT_ID)?.value : undefined;
    param.path = this.addForm.get(PATH)?.dirty ? this.addForm.get(PATH)?.value : undefined;
    param.perms = this.addForm.get(PERMS)?.dirty ? this.addForm.get(PERMS)?.value : undefined;
    // param.icon = this.addForm.get(ICON)?.dirty ? this.addForm.get(ICON)?.value : undefined;
    param.icon = this.selectedIcon;

    this.doUpdate(param);
  }

  doUpdate(param: UpdateMenuParam) {
    this._api.updateMenu(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK) {
        this._message.info("update Ok");
        this.resetModal();
        this.addMenuEvent.emit(true);
      } else {
        this._message.warning("update error: " + resp.message);
      }
    });
  }

  onSubmit(event: UIEvent) {
    event.preventDefault();

    if (this.editMode == EditMode.ADD) {
      this.onCreate();
    } else {
      this.onUpdate();
    }
  }

  onCancel(event: UIEvent) {
    event.preventDefault();
    this.addMenuEvent.emit(false);
  }

  onChange($event: string): void {
    const selected = this.addForm.get('parentId');
    console.log(`selected node ${selected}, event ${$event}`);
  }

  onIconClick(icon: string) {
    console.log(`icon clicked ${icon}`);
    this.selectedIcon = icon;
    this.addForm.get(ICON)?.patchValue(icon);
  }
  
  resetModal() {
    this.menu = undefined;
    this.editMode = EditMode.ADD;
    this.parentValue = undefined;
    this.menuTypes = [];
    this.submitted = false;
  }
  
}
